package com.gzsxy.config;

import com.gzsxy.exception.CustomWebResponseExceptionTranslator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.*;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.stereotype.Component;



/**
 * @author xiaolong
 * @version 1.0
 * @description: 认证授权Server端
 * @date 2021/11/4 17:19
 */
@Component
@EnableAuthorizationServer
public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter {


    /**
     * 令牌存储策略
     */
    @Autowired
    private TokenStore tokenStore;

    /**
     * 密码模式需要
     */
    @Autowired
    private AuthenticationManager authenticationManager;

    /**
     * 授权码模式需要
     */
    @Autowired
    private AuthorizationCodeServices authorizationCodeServices;

    /**
     *  采用查询数据库方式获取客户端信息
     */
    @Autowired
    private ClientDetailsService clientDetailsServices;

//    //生成JWT令牌存储策略
//    @Autowired
//    private JwtAccessTokenConverter accessTokenConverter;

    /**
     * 自定义异常处理类
     */
    @Autowired
    private CustomWebResponseExceptionTranslator customWebResponseExceptionTranslator;

    /**
     * 用户认证类
     */
    @Autowired
    private MemberDetailsService memberDetailsService;

    /**
     * redis连接工厂
     */
    @Autowired
    RedisConnectionFactory redisConn;




    /**
     * 令牌存储模式
     */
    @Autowired
    public TokenStore getRedistTokenStore(){
        return new RedisTokenStore(redisConn);
    }



    /**
     * @description: 配置endpoints的安全约束（允许表单认证） 开放接口
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        //allowFormAuthenticationForClients允许表单提交
        //checkTokenAccess打开这些端点以供使用。两个端点，用于检查令牌（/oauth/check_token和/oauth/token_key）
        security.allowFormAuthenticationForClients().tokenKeyAccess("permitAll()")
                .checkTokenAccess("permitAll()");

    }








    /**
     * 配置客户端详细信息服务
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

        //采用查询数据库方式获取客户端信息
        clients.withClientDetails(clientDetailsServices);
        //暂时使用内存方式  使用in-memory存储
//        clients.inMemory()
//                // appid
//                .withClient("mayikt") //客户端id
//                // appsecret 客户端密钥
//                .secret(passwordEncoder.encode("123456"))
//                // authorization_code授权码模式， password密码模式，"client_credentials","implicit","refresh_token"
//                .authorizedGrantTypes("authorization_code","password","client_credentials","implicit","refresh_token")
//                // 作用域  允许的授权范围
//                .scopes("all")
//                // 资源的id
//                .resourceIds("mayikt_resource")
//                //false跳转到授权页面
//                .autoApprove(false)
//                // 回调地址
//                .redirectUris("http://localhost:8080/user");

    }






    /**
     *  配置授权令牌访问端点
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
//        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(customTokenEnhancer()));

        endpoints
                //可以直接在授权Server端填入用户认证也可以在WebSecurityConfigurerAdapter中实现
                .userDetailsService(memberDetailsService)
                //密码模式需要
                .authenticationManager(authenticationManager)
                //授权码模式需要
                .authorizationCodeServices(authorizationCodeServices)
                //获取Token增强（用户信息扩展）
                .tokenEnhancer(new CustomTokenEnhancer())
                //令牌存储模式
                .tokenStore(getRedistTokenStore())
//                //令牌管理服务
//                .tokenServices(tokenService())
                //自定义异常处理类
                .exceptionTranslator(customWebResponseExceptionTranslator)
                //允许post提交
                .allowedTokenEndpointRequestMethods(HttpMethod.POST);
        //令牌管理服务  （存储模式以及有效期）
        DefaultTokenServices services = new DefaultTokenServices();
        //客户端信息服务 （从数据库中取）
        services.setClientDetailsService(clientDetailsServices);
        //是否开启支持refresh_token，此处如果之前没有配置，启动服务后再配置重启服务，可能会导致不返回token的问题，解决方式：清除redis对应token存储
        services.setSupportRefreshToken(true);
        //令牌存储策略
        services.setTokenStore(getRedistTokenStore());

         //使用jwt模式token令牌
//      TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
//      tokenEnhancerChain.setTokenEnhancers(Arrays.asList(accessTokenConverter));
//      services.setTokenEnhancer(tokenEnhancerChain);
        //令牌默认有效期2小时
        services.setAccessTokenValiditySeconds(7200);
        //刷新令牌默认有效期3天
        services.setRefreshTokenValiditySeconds(259200);
        services.setTokenEnhancer(endpoints.getTokenEnhancer());
        endpoints.tokenServices(services);
    }



}
